//package com.zxd.interview.transactions;
//
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.ApplicationContext;
//import org.springframework.jdbc.core.JdbcTemplate;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Propagation;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.math.BigDecimal;
//import java.sql.SQLException;
//import java.util.List;
//import java.util.Map;
//
///**
// * @author zhaoxudong
// * @version v1.0.0
// * @Package : com.zxd.interview.transactions
// * @Description : 事务回滚测试
// * @Create on : 2022/1/2 18:13
// **/
//@Service
//@Slf4j
//public class TransactionTestService {
//
//    // 随机异常触发flag
//    private static final boolean EXCEPTIN_FLAG = true;
//
//    @Autowired
//    private JdbcTemplate jdbcTemplate;
//
//    /**
//     * 1。 TransactionDefinition.PROPAGATION_REQUIRED 测试
//     * 2。 Propagation.SUPPORTS 测试
//     * 3。
//     */
//    //TransactionDefinition.PROPAGATION_REQUIRED
////    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
//    @Transactional(rollbackFor = Exception.class)
//    public void required(){
//        transactionTestService.requiredInner();
//        jdbcTemplate.update("update t_trans_test set amount=amount-100 where name='用户A'");
////        if(EXCEPTIN_FLAG){
////            throw new  RuntimeException("回滚事务");
////        }
//    }/*运行结果：
//    Propagation.REQUIRED
//    =========== 运行前数据准备重置数据 ========
//    ====== 运行后查询操作结果 ======
//    {id=1, name=用户A, amount=1000}
//    {id=2, name=用户B, amount=500}
//    java.lang.RuntimeException: 回滚事务
//
//    修复之前：
//    =========== 运行前数据准备重置数据 ========
//    ====== 运行后查询操作结果 ======
//    {id=1, name=用户A, amount=900}
//    {id=2, name=用户B, amount=600}
//    java.lang.RuntimeException: 回滚事务
//
//    修复之后：
//    =========== 运行前数据准备重置数据 ========
//    ====== 运行后查询操作结果 ======
//    {id=1, name=用户A, amount=1000}
//    {id=2, name=用户B, amount=500}
//    java.lang.RuntimeException: 回滚事务
//
//    Propagation.MANDATORY运行结果
//    org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
//
//    Propagation.NOT_SUPPORTED 运行结果：
//    ====== 运行后查询操作结果 ======
//    {id=1, name=用户A, amount=1000}
//    {id=2, name=用户B, amount=500}
//    org.springframework.dao.CannotAcquireLockException: StatementCallback; SQL [update t_trans_test set amount=amount+100 where name='用户B']; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
//
//    死锁，调整之后运行结果：
//    =========== 运行前数据准备重置数据 ========
//    2022-01-03 16:25:07.665  INFO 26477 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
//    2022-01-03 16:25:07.789  INFO 26477 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
//    ====== 运行后查询操作结果 ======
//    {id=1, name=用户A, amount=1000}
//    {id=2, name=用户B, amount=600}
//
//    java.lang.RuntimeException: 回滚事务
//
//    PROPAGATION_NESTED
//
//
//    */
//
////    @Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.NEVER)
////    @Transactional(rollbackFor = Exception.class, propagation = Propagation.MANDATORY)
////    @Transactional(rollbackFor = Exception.class, propagation = Propagation.NOT_SUPPORTED)
//    @Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
//    public void requiredInner(){
//        jdbcTemplate.update("update t_trans_test set amount=amount+100 where name='用户B'");
//        if(EXCEPTIN_FLAG){
//            throw new  RuntimeException("内部回滚事务");
//        }
//    }
//
//    /**
//     * 抛出不被处理的异常
//     * @throws SQLException
//     */
//    @Transactional(rollbackFor = RuntimeException.class)
//    public void throwErrorException() throws SQLException {
//        jdbcTemplate.update("update t_trans_test set amount=amount-100 where name='用户A'");
//        System.out.println("接受转账");
//        if(EXCEPTIN_FLAG){
//            throw new SQLException("转账失败");
//        }
//        jdbcTemplate.update("update t_trans_test set amount=amount+100 where name='用户B'");
//    }
//
//
//    /**
//     * 不抛出异常，导致不回滚
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public void nonThrowException(){
//        System.out.println("发起转账");
//        jdbcTemplate.update("update t_trans_test set amount=amount-1100 where name='用户A'");
//        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from t_trans_test where name='用户A'");
//        Map<String, Object> stringObjectMap = maps.get(0);
//        BigDecimal amount = new BigDecimal(stringObjectMap.get("amount").toString());
//        if(amount.compareTo(BigDecimal.ZERO) < 0){
//            log.error("余额不支持扣款");
//        }
//    }/*运行结果：
//    =========== 运行前数据准备重置数据 ========
//
//    没有抛出异常测试
//    发起转账
//    2022-01-02 23:04:26.672 ERROR 19583 --- [           main] c.z.i.t.TransactionTestService           : 余额不支持扣款
//    ====== 运行后查询操作结果 ======
//    {id=1, name=用户A, amount=-100}
//    {id=2, name=用户B, amount=500}
//    */
//
//    @Autowired
//    private TransactionTestService transactionTestService;
//
//    @Autowired
//    private ApplicationContext applicationContext;
//
//    /**
//     * 事务失效的第一种情况：非事务方法调用事务方法
//     * 修复方法：
//     * 1. 注入自己
//     * 2. 获取代理对象
//     */
////    @Transactional(rollbackFor = Exception.class)
//    public void nonTransactionUseTrasaction(){
//        System.out.println("发起转账");
////        jdbcTemplate.update("update t_trans_test set amount=amount-100 where name='用户A'");
//        // 常见方式：注入自己
////        transactionTestService.innerMethod();
//        // 使用代理对象方式1 ：AopContext.currentProxy()
////        TransactionTestService transactionTestService = (TransactionTestService) AopContext.currentProxy();
////        transactionTestService.innerMethod();
//        // 第三种方法，注入 ApplicationContext
////        TransactionTestService transactionTestService = (TransactionTestService) applicationContext.getBean("transactionTestService");
////        transactionTestService.innerMethod();
//        // 补充 - 获取Class: AopUtils.getTargetClass(yourObjectInstance);
////       AopUtils.getTargetClass(yourServiceClass);
//
//    }
//
//    @Transactional(rollbackFor = Exception.class)
//    protected void innerMethod(){
//        jdbcTemplate.update("update t_trans_test set amount=amount-100 where name='用户A'");
//        System.out.println("接受转账");
//        if(EXCEPTIN_FLAG){
//            throw new RuntimeException("转账失败");
//        }
//        jdbcTemplate.update("update t_trans_test set amount=amount+100 where name='用户B'");
//    }
//}
